package ListBook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Observable;
import java.util.Observer;

import javafx.collections.ObservableList;
import javafx.stage.Stage;

import org.controlsfx.dialog.Dialogs;

/**
 * ****************************************
 * FILENAME: NoteManager.java
 * ****************************************
 * Verwaltet die eine Liste von Notizen und enthaelt saemtliche Verwaltungsmethoden.
 *
 * @author Kove / HOEFI
 * @since 28.01.2015
 * @version 1.0
 */
@SuppressWarnings("deprecation")
public class NoteManager implements Observer {

  /**
   * Singleton-Instanz
   */
  private static NoteManager instance = null;
  /**
   * Notizliste
   */
  private ObservableList<Note> noteList = Utilities.createNewObservableList(null);

  /**
   * 'private' Konstruktor um neue Instanzierungen zu verhindern.
   * 
   * @author Kove / HOEFI
   * @since 01.02.2015
   */
  private NoteManager() {
  }

  /**
   * Gibt die Singleton-Instanz zurueck.
   * 
   * @author Kove / HOEFI
   * @since 01.02.2015
   * @return Notiz-Manager
   */
  public static NoteManager getInstance() {
    if (instance == null)
      instance = new NoteManager();
    return instance;
  }

  /**
   * Laedt alle Notizen
   * 
   * @author Kove / HOEFI
   * @throws SecurityException
   * @throws IOException
   * @throws ClassNotFoundException
   * @since 29.01.2015
   */
  public void loadNotes() throws SecurityException, IOException, ClassNotFoundException {
    File dataFolder = new File(ApplicationSettings.DATA_PATH);
    if (dataFolder.exists()) {
      for (File dataFile : dataFolder.listFiles()) {
        FileInputStream file = new FileInputStream(dataFile);
        ObjectInputStream stream = new ObjectInputStream(file);
        addAndObserveNote((Note) stream.readObject());
        stream.close();
      }
    }
  }

  /**
   * Speichert eine Notiz.
   * 
   * @author Kove / HOEFI
   * @since 24.02.2015
   * @param note
   *          Notiz-Objekt
   * @throws SecurityException
   * @throws IOException
   * @throws FileNotFoundException
   */
  public void saveNote(Note note) throws SecurityException, IOException, FileNotFoundException {
    File noteFile = new File(ApplicationSettings.DATA_PATH + note.getFileGUID());
    if (!noteFile.exists())
      noteFile.createNewFile();
    FileOutputStream file = new FileOutputStream(noteFile);
    ObjectOutputStream stream = new ObjectOutputStream(file);
    stream.writeObject(note);
    stream.close();
  }

  /**
   * @author Kove / HOEFI
   * @since 28.01.2015
   * @return Gibt Klassenmember "noteList" zurueck.
   */
  public ObservableList<Note> getNoteList() {
    return noteList;
  }

  /**
   * Generiert ein neues Notiz-Objekt und fuegt es der Notizliste hinzu.
   * 
   * @author Kove / HOEFI
   * @since 28.01.2015
   * @param title
   *          Titel der Notiz.
   * @return Gibt die generierte Notiz zurueck.
   * @throws Exception
   */
  public Note createNote(String title) throws Exception {
    checkTitle(title);
    Note note = new Note(title);
    addAndObserveNote(note);
    saveNote(note);
    return note;
  }

  /**
   * Loescht das entsprechende Notiz-Objekt aus der Notizliste.
   * 
   * @author Kove / HOEFI
   * @since 29.01.2015
   * @param note
   *          Zu loeschende Notiz.
   */
  public void removeNote(Note note) throws SecurityException {
    if (note != null){
      File noteFile = new File(ApplicationSettings.DATA_PATH + note.getFileGUID());
      noteFile.delete();
      noteList.remove(note);
    }
  }

  /**
   * Prueft ob der Titel gueltig ist (keine Duplikate, nicht leer)
   * 
   * @author Kove / HOEFI
   * @since 14.02.2015
   * @param title
   *          Titel der Notiz
   * @throws Exception
   */
  private void checkTitle(String title) throws Exception {
    String titleOriginal = title;
    if (title == null || title.isEmpty())
      throw new Exception("Es wurde kein Titel eingegeben.");
    title = title.toUpperCase();
    for (Note note : noteList) {
      if (note.getNoteTitle().toUpperCase().equals(title))
        throw new Exception("Es ist bereits eine Notiz mit dem Titel [" + titleOriginal + "] vorhanden.");
    }
  }

  /**
   * Fuegt eine neue Notiz in die Liste hinzu und ueberwacht die Notiz auf geaenderte Werte (autosave).
   * 
   * @author Kove / HOEFI
   * @since 24.02.2015
   * @param note
   *          Notiz-Objekt
   */
  private void addAndObserveNote(Note note) {
    note.addObserver(this);
    noteList.add(note);
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
   */
  @Override
  public void update(Observable observable, Object object) {
    try {
      saveNote((Note) object);
    } catch (SecurityException e) {
      Dialogs.create().owner(new Stage())
      .title(ApplicationSettings.APP_NAME + ": Speichern der Notiz")
      .masthead("Zugriff auf Datei verweigert.")
      .message(e.getMessage())
      .showException(e);
    } catch (FileNotFoundException e) {
      Dialogs.create().owner(new Stage())
      .title(ApplicationSettings.APP_NAME + ": Speichern der Notiz")
      .masthead("Datei wurde nicht gefunden.")
      .message(e.getMessage())
      .showException(e);
    } catch (IOException e) {
      Dialogs.create().owner(new Stage())
      .title(ApplicationSettings.APP_NAME + ": Speichern der Notiz")
      .masthead("Datei konnte nicht geoeffnet werden.")
      .message(e.getMessage())
      .showException(e);
    }

  }
}
